<?php

namespace app\socket\types;

use app\socket\object\Game;
use think\helper\Arr;
use think\helper\Str;

/**
 * 五子棋房间类
 * @property int $block 黑棋方
 * @property int $white 白棋方
 * @property array $observer 观看者
 * @property string $roomId 房间号
 * @property int $state 游戏状态 0:等待玩家加入 1:等待其他人准备 2:游戏进行中 3:游戏结束
 * @property int $round 游戏回合 0
 * @property int $count 游戏局数
 * @property int $win 胜利者的fd
 */
class FcRoom extends Game
{
    public $pk = "roomId";
    public $cacheKey = ["swoole", "room"];
    public $hidden = ['blockPlayer', 'whitePlayer', 'obPlayers', 'logger'];
    public $type = [
        'observer' => 'json'
    ];

    private $state = 0;
    private $round = 0;
    private $count = 0;
    private $win = 0;

    /**
     * 黑棋玩家
     *
     * @var FcPlayer
     */
    private $blockPlayer = null;
    /**
     * 白棋玩家
     *
     * @var FcPlayer
     */
    private $whitePlayer = null;



    /**
     * 观看者
     *
     * @var array
     */
    private $obPlayers = [];

    /**
     * 获取一个不存在房间号创建房间
     *
     *  SISMEMBER room:list 房间号 判断当前房间号是否已存在
     *  SADD room:list 房间号 向房间列表中加入一个房间号
     * @return string
     */
    public static function getNotExistRoom()
    {
        $obj = new FcRoom();
        $key = implode(":", ["swoole", "room", "list"]);
        while (true) {
            $roomId = "r" . Str::random(6, 1);
            if (!$obj->redis->SISMEMBER($key, $roomId)) {
                $obj->redis->sadd($key, $roomId);
                return $roomId;
            }
        }
    }

    /**
     * 添加一个玩家
     *
     * @param FcPlayer $player
     * @return $this
     */
    public function add($player)
    {
        if ($this->block && $this->block == $player->fd) {
            $this->blockPlayer = $player;
        } else if ($this->white && $this->white == $player->fd) {
            $this->whitePlayer = $player;
        } else if (!$this->block) {
            $this->block = $player->fd;
            $player->camp = 0;
            $this->blockPlayer = $player;
        } else if (!$this->white) {
            $this->white = $player->fd;
            $player->camp = 1;
            $this->whitePlayer = $player;
        } else {
            $player->camp = 2;
            if (!$this->observer) {
                $this->observer = [$player->fd];
            } else {
                $ob = $this->observer;
                array_push($ob, $player->fd);
                $this->observer = $ob;
            }
        }
        if (!$player->roomId) {
            $player->roomId = $this->roomId;
        }

        return $this;
    }

    /**
     * 从房间中移除一个玩家
     *
     * @param FcPlayer $player
     * @return $this
     */
    public function remove($player)
    {
        if ($this->block == $player->fd) {
            $this->block = 0;
            $this->state = 3;
        } else if ($this->white == $player->fd) {
            $this->white = 0;
            $this->state = 3;
        } else {

            $ob = $this->observer;

            $index = array_search($player->fd, $ob);
            if ($index !== false) {
                array_splice($ob, $index, 1);
                $this->observer = $ob;
            }
        }
        $this->save();



        //如果当前房间内 没有人了 那么 删除房间日志 删除房间
        if (!$this->block && !$this->white && !count($this->observer)) {
            $this->logger->delete();
            $this->delete();
            //房间列表中也要删除
            $this->redis->SREM(implode(":", ["swoole", "room", "list"]), $this->roomId);
        }
        return $this;
    }



    /**
     * 获取黑棋方玩家
     *
     * @return FcPlayer
     */
    public function getBlockPlayerAttr()
    {
        if (!$this->blockPlayer && $this->block) {
            $p = FcPlayer::find($this->block);
            $this->blockPlayer = $p->fd ? $p : null;
        }
        return $this->blockPlayer;
    }

    /**
     * 获取白棋方玩家
     *
     * @return FcPlayer
     */
    public function getWhitePlayerAttr()
    {
        if (!$this->whitePlayer && $this->block) {
            $p = FcPlayer::find($this->white);
            $this->whitePlayer = $p->fd ? $p : null;
        }
        return $this->whitePlayer;
    }

    /**
     * 获取所有观看者的信息
     *
     * @return array
     */
    public function getObPlayersAttr()
    {
        $this->obPlayers = [];
        if ($this->observer) {
            foreach ($this->observer as $fd) {
                $this->obPlayers[] = FcPlayer::find($fd);
            }
        }
        return $this->obPlayers;
    }

    /**
     * 获取相对于当前fd的对方fd
     *
     * @param int $fd fd只能是玩家
     * @return int|bool
     */
    public function getOtherFd($fd)
    {
        if ($this->block == $fd) {
            return $this->white;
        } else if ($this->white == $fd) {
            return $this->block;
        }
        return false;
    }

    /**
     * 获取房间日志
     *
     * @return FcLog
     */
    public function getLoggerAttr()
    {
        if (!isset($this->logger)) {
            $this->logger = new FcLog($this->roomId);
        }
        return $this->getData("logger");
    }


    /**
     * 悔棋
     *
     * @param int $fd 同意悔棋请求的fd
     * @return void
     */
    public function backChess($fd)
    {
        $logger = new FcLog($this->roomId);
        $logs = $logger->getLastThree();

        //请求悔棋的fd
        $bfd = $this->getOtherFd($fd);
        $count = count($logs);
        $size = 0;
        $cross = false;
        $delete = [];
        if ($count) {
            while ($count--) {
                $log = array_pop($logs);
                array_push($delete, $log['index']);
                $size += 1;
                if ($log['fd'] == $bfd) {
                    $count = 0;
                    $crossLog = array_pop($logs);
                    if ($crossLog) {
                        $cross = $crossLog['index'];
                    }
                }
            }
        }
        if ($size) {
            $logger->remove($size);
        }
        return [$delete, $cross];
    }
}
